How to boot Linux using UEFI with Secure Boot ?¶
Preview¶
In this tutorial, we will describe every steps to secure the boot of Linux on a PC. We will learn to backup existing certificates from the UEFI and write our own certificates. Moreover, you will also see how to sign our grub bootloader, kernel and initrd. Then, you will be able to configure the grub configuration file in order to only load signed kernel and initrd. Finally, we will protect the grub configuration file.
Here, I will be using a Centos 7 distribution, if you are using another check the documentation of your distribution for any problem or further information.
References¶
- For an overview of Secure Boot on Linux check Rodsbooks article.
- For further information check ArchLinux documentation on Secure Boot.
- For an EFI installation guide and how configure the Secure Boot check Gentoo documentation.
Contents¶
- Check Secure Boot status.
- Backup existing certificates from the UEFI.
- Write your own certificates.
- Sign your own grub / kernel / initrd.
- Configure your grub.cfg to only load signed kernel and initrd.
- Add a password protection to GRUB2.
- Annexes :
- A) Install sbsigntools and efitools on CentOS.
Prerequisite¶
- A Linux distribution installed and booting with UEFI on a PC.
- Disable Secure Boot in your BIOS.
You can also use a Virtual Environment following this tutorial.
Dependencies¶
- Install sbsigntools.
- Install efitools.
If you are using Centos 7 distribution, check how to install them in Annexe A.
Check Secure Boot status¶
To verify if your computer has booted with Secure Boot, type the following command :
$ bootctl status
In order to start this tutorial you need to have it disabled. If it is not go to your BIOS and disable it.
Backup existing certificates from the UEFI¶
In this section, we will backup the public keys / certificates from the UEFI keystore :
- The Platform Key (PK) is a variable where the public key given by the hardware vendor (ex : Dell, HP, Asus, ...) is stored.
- The Key Exchange Key (KEK) is a variable which can contains one or more public keys. Usually, Microsoft store his public key here.
- The Database (db) is a variable containing a signature database commonly filled with public keys. It is used as a boot executable whitelist.
- The Database Blacklist (dbx) is a variable similar to the db, but it contains the boot executable blacklist, also called "revoked keys/signatures".
Thoose variables are used to control the Secure Boot process.
Prepare the backup directory and give it only root access :
$ mkdir -p secu-os/backup $ chmod -v 700 secu-os/ $ cd secu-os/backup/
Backup actual efi keys :
$ efi-readvar -v PK -o old_PK.esl $ efi-readvar -v KEK -o old_KEK.esl $ efi-readvar -v db -o old_db.esl $ efi-readvar -v dbx -o old_dbx.esl
Warning : don't forget the
-o
option or your variable will be dumped as text and you wont be able to reload them.
Write your own certificates¶
Now we will create a new PK, KEK and kernel-signing keypair (db) with openssl
.
Keys caracteristics (source) :
- X.509 certificate format for the public key.
- RSA asymmetric cryptosystem, with a 2048 bit key length.
- Have 10 years (3650 days) to run until expiry.
- Use SHA-256 as the public key's message digest.
Prepare the efikeys directory :
$ cd secu-os/ $ mkdir efikeys $ cd efikeys/
Create the keys with openssl :
$ openssl req -new -x509 -newkey rsa:2048 -subj "/CN=tutorial's platform key/" -keyout PK.key -out PK.crt -days 3650 -nodes -sha256 $ openssl req -new -x509 -newkey rsa:2048 -subj "/CN=tutorial's key-exchange-key/" -keyout KEK.key -out KEK.crt -days 3650 -nodes -sha256 $ openssl req -new -x509 -newkey rsa:2048 -subj "/CN=tutorial's kernel-signing key/" -keyout db.key -out db.crt -days 3650 -nodes -sha256
Each commands provide a private key and a certificates.
Make the private key readable only by root :
$ chmod -v 400 *.key
Work In Progress : In order, to more protect the private keys, we are looking at encrypted file systems.
Sign your own grub / kernel / initrd¶
Update UEFI keystore with our own keys¶
Before signing our grub, kernel or initrd, we need to update the UEFI keystore variables with the keys that we have just created.
Some informations about keys format (source):
- .key PEM format private keys for EFI binary and EFI signature list signing.
- .crt PEM format certificates for sbsign.
- .cer DER format certificates for firmware.
- .esl Certificates in EFI Signature List for KeyTool and/or firmware.
- .auth Certificates in EFI Signature List with authentication header (i.e. a signed certificate update file) for KeyTool and/or firmware.
Create a GUID for owner identification :
$ cd secu-os/efikeys/ $ uuidgen --random > GUID.txt
Prepare PK for installation in EFI :
$ cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl $ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth
The first command convert a
certificate
into aEFI signature list
.The second one sign the
EFI signature list
. In this case, we sign it with the PK private key.Prepare KEK for installation in EFI :
$ cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl $ sign-efi-sig-list -g "$(< GUID.txt)" -a -k PK.key -c PK.crt KEK KEK.esl KEK.auth
We add
-a
option to append to the file instead of replace it.We use PK private key to sign the signature list.
Prepare db for installation in EFI :
$ cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl $ sign-efi-sig-list -g "$(< GUID.txt)" -a -k KEK.key -c KEK.crt db db.esl db.auth
Same, we use here
-a
option.We use KEK private key to sign the signature list.
Prepare dbx for installation in EFI :
$ sign-efi-sig-list -k KEK.key -c KEK.crt dbx ../backup/old_dbx.esl old_dbx.auth
For the dbx, we just restore the old one and sign it with the KEK private key.
Crete DER version of our 3 public keys (certificates) :
$ openssl x509 -outform DER -in PK.crt -out PK.cer $ openssl x509 -outform DER -in KEK.crt -out KEK.cer $ openssl x509 -outform DER -in db.crt -out db.cer
For dual boot, compound (old+new) in order to save microsoft signatures :
$ cat old_KEK.esl KEK.esl > compound_KEK.esl $ cat old_db.esl db.esl > compound_db.esl $ sign-efi-sig-list -k PK.key -c PK.crt KEK compound_KEK.esl compound_KEK.auth $ sign-efi-sig-list -k KEK.key -c KEK.crt db compound_db.esl compound_db.auth
Entering setup mode (clearing keystore)¶
To enter in setup mode, first rebbot the machine :
$ reboot
Then, enter in your BIOS and perform :
- Clear UEFI secure boot variable
- Save changes
- Restart your machine
Note : in some computers you will have to enable custom keys in your BIOS.
Installing new keys into the keystore¶
Verify that the secure boot variables are cleared :
$ efi-readvar
Expected output :
Variable PK has no entries Variable KEK has no entries Variable db has no entries Variable dbx has no entries
Return to your efikeys directory and update keystore with your own signatures :
$ cd secu-os/efikeys/ $ efi-updatevar -e -f ../backup/old_dbx.esl dbx $ efi-updatevar -e -f db.esl db $ efi-updatevar -e -f KEK.esl KEK $ efi-updatevar -f PK.esl PK
The
-e
option specifies that an EFI signature list file have to be loaded.The
-f
option precise the filename.Note : for dual boot user replace
db.esl
,KEK.esl
bycompound_db.esl
,compound_KEK.esl
.Backup your installed certificates :
$ cd ../backup/ $ efi-readvar -v PK -o new_PK.esl $ efi-readvar -v KEK -o new_KEK.esl $ efi-readvar -v db -o new_db.esl $ efi-readvar -v dbx -o new_dbx.esl
Verify the content of installed variables :
$ efi-readvar
Sign your grub bootloader¶
Backup your grub bootloader :
$ su root $ cd secu-os/backup/ $ cp /boot/efi/EFI/centos/grubx64.efi grubx64.efi.bak
Sign the grub bootloader :
$ cd secu-os/efikeys/ $ sbsign --key db.key --cert db.crt --output /boot/efi/EFI/centos/grubx64.efi /boot/efi/EFI/centos/grubx64.efi
We use
Sign your kernel¶
Backup your kernel :
$ su root $ cd secu-os/backup/ $ cp /boot/vmlinuz-xxx vmlinuz-xxx.bak
Sign the kernel :
$ cd secu-os/efikeys/ $ sbsign --key db.key --cert db.crt --output /boot/vmlinuz-xxx /boot/vmlinuz-xxx
Sign your initrd¶
Backup your initrd :
$ su root $ cd secu-os/backup/ $ cp /boot/initramfs-xxx initramfs-xxx.bak
At the point, sbsigntools don't provide the possibility to sign the initrd. So we will use an other tool named gpg :
Work In Progress : miss some steps to generate GPG.key.
$ gpg --default-key GPG.key --detach-sign /boot/initramfs-xxx.img
GRUB only load signed kernel¶
Backup your grub.cfg :
$ su root $ cd secu-os/backup/ $ cp /boot/efi/EFI/centos/grub.cfg grub.cfg.bak
Edit your grub.cfg and add this at the top of the file :
set check_signatures=enfore export check_signatures
Add a password protection to GRUB¶
To install password to "add" a little security on Grub2, you need to execute this command to set a new password :
$ grub2-setpassword
After that, in the "grub.cfg" file, you have to prevent "bypass" of password by removing all arguments "--unrestricted".
It has at least two ways to bypass Grub2 password for use of unsigned load :
- Accessing the grub.cfg file by UEFI Shell and add argument/option "--unrestricted" will disable password protection.
- Or delete the file "user.cfg" (on the same directory of "grub.cfg" by accessing UEFI Shell.
Warning : you need to be aware that all manual modification (like manual password configuration or signatures check) in grub.cfg will be erase by an update of grub for example with this command :
$ grub2-mkconfig -o /boot/grub2/grub.cfg
I advise you to do all modification like setting password directly in one of the configuration files used to build "grub.cfg". These files can be found in /etc/grub.d.
For example, you can set in file "01_users" :
#!/bin/sh -e
cat << EOF
set superusers="root"
password_pbkdf2 root "Your SHA password here"
set check-signatures = enforce
EOF
Like that, each time your "grub.cfg" will be regenerate, your changes will always be present to the grub configuration
Testing phase¶
Work In Progress
Conclusion¶
If you think that with the features we have done you have completly secure the boot process, then you are wrong. We just add some difficulties to break it and we will see in other articles ahow to add more protection by for example protect the grub.cfg file.
Annexes¶
A) Install sbsigntools and efitools¶
Create a work directory and install repositories in it :
$ mkdir -p secu-os/install
Use git clone or wget to download dependencies :
$ cd secu-os/install/ $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git
Proceed installations :
$ cd sbsigntools/ $ ./autogen.sh $ ./configure $ make check $ make install $ make installcheck $ cd ../efitools/ $ make $ make install
Note : you will certainly need to install some other packages, check your errors during compilation.
Help : If you have troubles during the installation of efitools, try the version 1.8.0.